<!doctype html>
<html>

<head>
	<meta http-equiv="Pragma" content="no-cache" />
	<meta http-equiv="Cache-Control" content="no-cache" />
	<meta http-equiv="Expires" content="0" />
	<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
	<meta name="viewport" content="width=device-width,initial-scale=1.0,user-scalable=no" />
	<title>奇异博士-传送门</title>
</head>
<style>
	html,
	body,
	canvas {
		margin: 0;
		padding: 9;
	}

	html,
	body {
		width: 100%;
		height: 100%;
	}

	body {
		overflow: hidden;
	}

	canvas {
		/* filter: blur(5px); */
	}
</style>

<body bgcolor="#000000">
	<canvas id="canvas"></canvas>
</body>
<script>
	var canvas = document.getElementById("canvas");
	canvas.style.position = "absolute";
	canvas.style.top = 0;
	var w = window.innerWidth;
	var h = window.innerHeight;
	canvas.width = w;
	canvas.height = h;
	ctx = canvas.getContext("2d");
	ctx.lineWidth = 1

	var g = 0.07
	var damping = 0.99
	var MIN_SPEED_X = 0.5


	var center = {
		x: w / 2,
		y: h / 2
	}
	var list = []
	/**
	 * 金黄：#FFD700 rgb(225,215,0)
	 * 深红：#8B0000 rgb(139,0,0)
	 */
	var MAX_LIMIT_AND_LEN = 41 // init中 limit + len的最大值，脱离圆周运动的最大步长
	var START_COLOR = { r: 255, g: 215, b: 80 }
	var END_COLOR = { r: 139, g: 0, b: 0 }
	var STEP_COLOR = {
		r: (START_COLOR.r - END_COLOR.r) / MAX_LIMIT_AND_LEN,
		g: (START_COLOR.g - END_COLOR.g) / MAX_LIMIT_AND_LEN,
		b: (START_COLOR.b - END_COLOR.b) / MAX_LIMIT_AND_LEN,
	}
	var MAX_RADIUS = 120 // 半径
	var SKYLINE = h / 2 + MAX_RADIUS + 30 // 地平线高度
	var MAX_COUNT = 42
	var STEP_RADIUS = 0.4
	var STEP_COUNT = 0.3
	var count = 1
	var radius = 50

	function init() {
		if (count < MAX_COUNT) count += STEP_COUNT
		if (radius < MAX_RADIUS) radius += STEP_RADIUS
		for (var i = 0; i < count; i++) {
			var deg = Math.random() * Math.PI * 2 // 角度
			var x = center.x + Math.cos(deg) * r // x位置
			var y = center.y + Math.sin(deg) * r // y位置
			var r = radius + Math.random() * 4 // 半径
			var step = 0.045 + Math.random() * 0.04 // 角速度
			var type = 'round' // 圆心运动
			var limit = ~~(Math.random() * 30) + 18 // 脱离圆心运动后运动的步长
			var len = 2 + ~~(Math.random() * 3) // 显示长度
			var color = { r: 255, g: 200 + ~~(Math.random() * 30), b: ~~(Math.random() * START_COLOR.b) } // 初始化颜色
			list.push({
				x, y, r, step, deg, type, limit, len, color, trail: [{ x, y }]
			})
		}
	}

	function update() {
		var init_damping = 0.55 + (MAX_RADIUS - radius) * 0.005 // 脱离圆心运动的元素，速度做一次衰减
		list.forEach(item => {
			var random = Math.random()
			if (item.type === 'round') {
				item.deg += item.step
				if (radius < MAX_RADIUS) item.r += STEP_RADIUS
				item.x = center.x + Math.cos(item.deg) * item.r
				item.y = center.y + Math.sin(item.deg) * item.r
				if (random < 0.1) {
					var speed = item.step * item.r
					item.type = 'parabola'
					item.sx = Math.cos(item.deg + Math.PI / 2) * speed * init_damping
					item.sy = Math.sin(item.deg + Math.PI / 2) * speed * init_damping
					if (item.sy < 0) {
						item.len += 2
					}
				}
			} else {
				item.sx *= damping
				item.sy *= damping
				item.sy += g
				item.x += item.sx
				item.y += item.sy
				if (item.y > SKYLINE) {
					item.sy = - Math.abs(item.sy) // 超过地平线之后，Y方向反弹
					item.sy *= random * 0.5 + 0.5  // 碰撞之后速度衰减
					item.sx *= random * 0.5 + 0.5
				}
				item.limit -= 1
				if (random > 0.5) { // 颜色随机衰减
					item.color.r = Math.max(0, ~~(item.color.r - STEP_COLOR.r))
					item.color.g = Math.max(0, ~~(item.color.g - STEP_COLOR.g))
					item.color.b = Math.max(0, ~~(item.color.b - STEP_COLOR.b))
				}
			}
			item.trail.unshift({ x: item.x, y: item.y })
			item.trail = item.trail.slice(0, Math.max(0, Math.min(item.len, item.len + item.limit)))
		})
		list = list.filter(item => item.trail.length > 0)
	}

	function draw() {
		ctx.clearRect(0, 0, w, h)
		list.forEach(item => {
			ctx.beginPath()
			item.trail.forEach((trail, index) => {
				if (index === 0) {
					ctx.moveTo(trail.x, trail.y)
				} else {
					ctx.lineTo(trail.x, trail.y)
				}
			})
			ctx.strokeStyle = 'rgb(' + item.color.r + ',' + item.color.g + ',' + item.color.b + ')'
			ctx.stroke()
		})
	}

	function step() {
		init()
		update()
		draw()
		requestAnimationFrame(step)
	}
	requestAnimationFrame(step)
</script>

</html>